package com.sh.diy;

import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * @Auther: sh
 * @Version 1.0
 * @Description: 线程池
 */
public class MyThreadPool {

    // 引入阻塞队列
    MyBlockQueue<Runnable> blockQueue;

    final Set<MyThread> set = new HashSet<>();

    // 核心线程数
    int corePoolSize;
    long timeOut;
    TimeUnit timeUnit;

    // 引入拒绝策略
    MyRejectPolicy<Runnable> myRejectPolicy;

    public MyThreadPool(MyBlockQueue<Runnable> blockQueue, int corePoolSize, long timeOut, TimeUnit timeUnit, MyRejectPolicy<Runnable> myRejectPolicy) {
        this.blockQueue = blockQueue;
        this.corePoolSize = corePoolSize;
        this.timeOut = timeOut;
        this.timeUnit = timeUnit;
        this.myRejectPolicy = myRejectPolicy;
    }


    public void execute(Runnable task) {
        synchronized (set){
            if(set.size()<corePoolSize){
                MyThread myThread = new MyThread(task);
                set.add(myThread);
                myThread.start();
            }else {
                // 核心线程满了，方法一，放到阻塞队列中等待
//                blockQueue.put(task);
                // 方法二、，如果满了就执行拒绝策略
                blockQueue.tryPut(this.myRejectPolicy, task);
            }
        }
    }

    public class MyThread extends Thread {

        //接受任务
        private Runnable task;

        public MyThread(Runnable task) {
            this.task = task;
        }

        @Override
        public void run() {
            // 循环执行任务
            while (task != null || (task == blockQueue.poll(timeOut, timeUnit))) {
                try {
                    task.run();
                } catch (Exception e) {
                    throw new RuntimeException(e);
                } finally {
                    task = null;
                }
            }
            // 循环执行完后，说明队列中没有任务，且也没有新任务
            // 任务已经全部执行完了，移除执行该任务的线程
            // 所以：在任务完成后，将线程从线程池中移除，避免资源浪费。
            // this 指当前类的实例化对象，也就是 new MyThread()
            // 由于到时候有多个线程，也操作这个set集合，所以也需要锁
            synchronized (set) {
                set.remove(this);
            }

        }
    }


}

